#ifdef __x86_64__
#define BLOCK_SIZE 36  // 64bit-system  size_t size[8 bytes]; (void*) next[8 bytes]; int free[4 bytes];
#endif

#ifdef __i386__
#define BLOCK_SIZE 12  // 32bit-system  size_t size[4 bytes]; (void*) next[4 bytes]; int free[4 bytes];
#endif


#include <unistd.h>

typedef struct s_block* t_block;

struct s_block
{
    size_t size;  // block size
    t_block prev;  // point to prev block
    t_block next;  // point to next block
    int free;  // whether the block is available
    void *ptr;  // a pointer to the allocated block
    char data[1];  // gurantee byte precision
};

/**
 * @brief find the first block width enough in heap
 * @param  last             last visited block
 * @param  size             size required
 * @return t_block/NULL     founded block / NULL
 */
t_block find_block(t_block *last, size_t size);

/**
 * @brief lack space, extend heap
 * @param  last             last visited block
 * @param  s                size to expand
 * @return t_block          block generated in the expansion
 */
t_block extend_heap(t_block last, size_t s);

/**
 * @brief split block into 2 and use only the 1st part
 * @param  b                block to split
 * @param  s                size required
 * @return t_block          block with required size
 */
t_block split_block(t_block b, size_t s);

/**
 * @brief first fit malloc
 * @param  size             My Param doc
 * @return void* 
 */
void *ff_malloc(size_t size);

/**
 * @brief alloc multiple blocks at a time
 * @param  number           num of blocks to alloc
 * @param  size             size of each block
 * @return void* 
 */
void *ff_calloc(size_t number, size_t size);

/**
 * @brief fuse current block and the next one
 * @param  b                block pointer
 * @return t_block 
 */
t_block fusion(t_block b);

/**
 * @brief Get the block from data[] addr
 * @param  p                data[] addr
 * @return t_block 
 */
t_block get_block(void *p);

/**
 * @brief verify whether the pointer is in heap
 * @param  p                pointer to valid
 * @return int 
 */
int valid_addr(void *p);

/**
 * @brief 
 * @param  p                pointer -> block to be free
 */
void ff_free(void *p);

/**
 * @brief 
 * @param  src              source block
 * @param  dst              destination block
 */
void copy_block(t_block src, t_block dst);
